package org.jsola.hr.service.excel;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.jsola.common.BeanKit;
import org.jsola.exception.ParamException;
import org.jsola.hr.dto.BulkEditCheckWrongsDTO;
import org.jsola.hr.entity.EmpInfoDO;
import org.jsola.hr.entity.EmpSocInfoDO;
import org.jsola.hr.entity.EmpSocItemDO;
import org.jsola.hr.entity.EmpSocMonthDO;
import org.jsola.hr.service.IEmpInfoService;
import org.jsola.hr.service.IEmpSocInfoService;
import org.jsola.hr.service.IEmpSocItemService;
import org.jsola.hr.service.IEmpSocMonthService;
import org.jsola.hr.vo.BulkEditWrongsVO;
import org.jsola.user.core.TokenUser;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lyh
 */

@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
public class EmpSocImportListener extends BaseAnalysisEventListener<Map<Integer, String>> {

    /**
     * 表头数据
     */
    private Map<Integer, String> allHeadMap;

    /**
     * 重复的表头
     */
    private List<String> repeatHead = new ArrayList<>();

    /**
     * 数据
     */
    private Map<String, String> dataMap;

    /**
     * 转变结构后的数据
     */
    private List<Map<String, String>> dataList = new ArrayList<>();

    /**
     * List最大盛装数据条数
     */
    private static final Integer MAX_COUNT = 1000;

    /**
     * 参保月份Id
     */
    private String monthId;

    /**
     * 错误数据
     */
    private BulkEditWrongsVO bulkEditWrongsVO = new BulkEditWrongsVO();

    /**
     * 导入的当月正常应缴的参保信息<员工Id,参保信息>
     */
    private Map<String, EmpSocInfoDO> socInfoMap;

    /**
     * 错误数据列表
     */
    List<Map<String, String>> errorList = new ArrayList<>();

    /**
     * 需要入库的数据；
     */
    List<BulkEditCheckWrongsDTO> successList = new ArrayList<>();

    /**
     * 用来校验是否有重复数据
     */
    List<String> nameList = new ArrayList<>();

    @Override
    public void saveData() {
        log.info("{}条数据，开始存储数据库！", dataList.size());
        ParamException.notEmpty(dataList, "没有数据需要入库");
        ParamException.notNull(tokenUser, "没有设置当前登录用户");
        IEmpSocInfoService empSocInfoService = BeanKit.getBean(IEmpSocInfoService.class);
        IEmpSocMonthService empSocMonthService = BeanKit.getBean(IEmpSocMonthService.class);
        EmpSocMonthDO empSocMonthDO = empSocMonthService.selectDOById(monthId, tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(socInfoMap)) {
            // 查询这个月的参保信息记录
            List<EmpSocInfoDO> empSocInfoList = empSocInfoService.selectNormalInfoByMonthId(monthId, tokenUser);
            socInfoMap = empSocInfoList.stream()
                    .collect(Collectors.toMap(EmpSocInfoDO::getEmpId, v -> v));
        }
        for (Map<String, String> dataMap : dataList) {
            BulkEditCheckWrongsDTO checkWrongs = checkWrongs(dataMap, socInfoMap, nameList,
                    empSocMonthDO.getCompanyId(), tokenUser);
            if (checkWrongs.getHaveWrongs()) {
                errorList.add(dataMap);
            } else {
                checkWrongs.setDataMap(dataMap);
                successList.add(checkWrongs);
            }
        }
        empSocInfoService.bulkEdit(successList, tokenUser);
        if (ObjectUtils.isEmpty(bulkEditWrongsVO.getCount())) {
            bulkEditWrongsVO.setCount(dataList.size());
        } else {
            bulkEditWrongsVO.setCount(bulkEditWrongsVO.getCount() + dataList.size());
        }
    }


    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        // 获取行的索引
        log.info("解析到一条数据:{}", JSON.toJSONString(data));
        // 本来data是<下标,数据>的结构,把它变成<表头,数据>的结构
        Map<String, String> newData = new LinkedHashMap<>();
        for (Integer headIndex : allHeadMap.keySet()) {
            String dateValue = data.get(headIndex);
            if (StringUtils.isEmpty(dateValue)) {
                newData.put(allHeadMap.get(headIndex), "");
            } else {
                newData.put(allHeadMap.get(headIndex), dateValue);
            }
        }
        dataList.add(newData);
        if (dataList.size() >= MAX_COUNT) {
            // 入库
            saveData();
            // 存储完成清理 list
            dataList.clear();
            successList.clear();
        }
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        log.info("所有表头:{}", JSON.toJSONString(headMap));
        allHeadMap = headMap;
        // 寻找重复表头
        List<String> headValue = new ArrayList<>();
        for (String value : headMap.values()) {
            if (headValue.contains(value)) {
                repeatHead.add(value);
                continue;
            }
            headValue.add(value);
        }
        headValue.add("错误原因");
        bulkEditWrongsVO.setHead(headValue);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        if (!CollectionUtils.isEmpty(dataList)) {
            saveData();
        }
    }

    private BulkEditCheckWrongsDTO checkWrongs(Map<String, String> dataMap, Map<String, EmpSocInfoDO> empSocInfoMap,
                                               List<String> nameList, String companyId, TokenUser tokenUser) {
        IEmpInfoService empInfoService = BeanKit.getBean(IEmpInfoService.class);
        IEmpSocItemService empSocItemService = BeanKit.getBean(IEmpSocItemService.class);
        BulkEditCheckWrongsDTO result = new BulkEditCheckWrongsDTO();
        String name = dataMap.get("姓名");
        String idCard = dataMap.get("身份证号");
        String serviceCost = dataMap.get("服务费");
        if (StringUtils.isEmpty(name) || StringUtils.isEmpty(idCard)) {
            dataMap.put("错误原因", "员工信息缺失");
            result.setHaveWrongs(true);
            return result;
        }
        if (nameList.contains(name)) {
            dataMap.put("错误原因", "员工信息重复");
            result.setHaveWrongs(true);
            return result;
        }
        nameList.add(name);
        EmpInfoDO empInfoDO = empInfoService.selectIdCardAndPhone(idCard, name, companyId, tokenUser);
        if (ObjectUtils.isEmpty(empInfoDO)) {
            dataMap.put("错误原因", "员工无法匹配");
            result.setHaveWrongs(true);
            return result;
        }
        EmpSocInfoDO empSocInfoDO = empSocInfoMap.get(empInfoDO.getId());
        result.setEmpSocInfoDO(empSocInfoDO);
        if (ObjectUtils.isEmpty(empSocInfoDO)) {
            dataMap.put("错误原因", "员工无法匹配");
            result.setHaveWrongs(true);
            return result;
        }
        if(!StringUtils.isEmpty(serviceCost)){
            try {
                new BigDecimal(serviceCost);
            } catch (Exception e) {
                dataMap.put("错误原因", "服务费格式错误");
                result.setHaveWrongs(true);
                return result;
            }
        }
        List<EmpSocItemDO> empSocItemList = empSocItemService.selectByEmpSocId(empSocInfoDO.getId(), tokenUser.getSiteId());
        result.setEmpSocItemList(empSocItemList);
        Map<String, EmpSocItemDO> itemMap = empSocItemList.stream()
                .collect(Collectors.toMap(EmpSocItemDO::getItemName, v -> v));
        for (String itemName : dataMap.keySet()) {
            if ("姓名".equals(itemName) || "身份证号".equals(itemName) || "服务费".equals(itemName)) {
                continue;
            }
            String itemCardinalityStr = dataMap.get(itemName);
            try {
                EmpSocItemDO empSocItemDO = itemMap.get(itemName);
                if (!StringUtils.isEmpty(itemCardinalityStr)) {
                    if (ObjectUtils.isEmpty(empSocItemDO)) {
                        dataMap.put("错误原因", "参保基数无法匹配");
                        result.setHaveWrongs(true);
                        return result;
                    }
                    BigDecimal itemCardinality = new BigDecimal(itemCardinalityStr);
                    if (itemCardinality.compareTo(BigDecimal.ZERO) <= 0) {
                        dataMap.put("错误原因", "参保数值异常");
                        result.setHaveWrongs(true);
                        return result;
                    }
                }
            } catch (Exception e) {
                dataMap.put("错误原因", "参保数值异常");
                result.setHaveWrongs(true);
                return result;
            }
        }
        result.setHaveWrongs(false);
        return result;
    }
}
